package de.tu_darmstadt.gdi1.xcom.model;

import java.util.LinkedList;
import java.util.List;

import de.tu_darmstadt.gdi1.framework.interfaces.IStepManager;
import de.tu_darmstadt.gdi1.framework.model.GameData;
import de.tu_darmstadt.gdi1.framework.utils.Point;
import de.tu_darmstadt.gdi1.xcom.controller.ai.XcomMediumAI;
import de.tu_darmstadt.gdi1.xcom.controller.ai.XcomSimpleAI;
import de.tu_darmstadt.gdi1.xcom.controller.events.GameStateEnum;
import de.tu_darmstadt.gdi1.xcom.model.elements.*;

public class XcomGameData extends GameData<GameElement> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6086384674376195905L;

	private String nextLevel;
	private String level;
	private XcomTeam team1;
	private XcomTeam team2;
	private int playedRounds;
	private int maxRounds;

	private GameStateEnum gameState;
	private GameStateEnum tempGameState;

	private boolean team1IsActive;

	public void setTeam1IsActive(boolean team1IsActive) {
		this.team1IsActive = team1IsActive;
	}

	public int getPlayedRounds() {
		return playedRounds;
	}

	public void setPlayedRounds(int playedRounds) {
		this.playedRounds = playedRounds;
	}

	public int getMaxRounds() {
		return maxRounds;
	}

	public void setMaxRounds(int maxRounds) {
		this.maxRounds = maxRounds;
	}

	public XcomGameData(IStepManager<GameElement> aStepManager) {
		super(aStepManager);
		this.team1IsActive = true;
	}

	@Override
	public boolean isLost() {
		// TODO: mission-aims
		// currently, a game is lost of all players have 0 actionpoints or are
		// dead and aliens
		// are still living
		if (playedRounds >= maxRounds)
			return true;
		return team1.isDefeated();
	}

	public GameStateEnum getGameState() {
		return gameState;
	}

	public void setGameState(GameStateEnum gameState) {
		this.gameState = gameState;
	}

	@Override
	public boolean isPaused() {
		return GameStateEnum.PAUSED == gameState;
	}

	@Override
	public boolean isRunning() {
		return gameState != GameStateEnum.FINISHED;
	}

	@Override
	public boolean isWon() {
		// TODO: mission-aims
		// currently, a game is won if there are all aliens dead and at least
		// one player is living
		if (playedRounds >= maxRounds && !team2.isDefeated())
			return false;
		return !team1.isDefeated() && team2.isDefeated();
	}

	public void setTeam(XcomTeam team, boolean team1) {
		if (team1)
			this.team1 = team;
		else
			this.team2 = team;

	}

	public XcomTeam getTeam(boolean team1) {
		if (team1)
			return this.team1;
		return this.team2;
	}

	private List<Mob> getMobs(boolean team1) {
		List<Mob> returnList = new LinkedList<Mob>();
		List<Point> positions;
		if (team1)
			positions = this.team1.getMobPositions();
		else
			positions = this.team2.getMobPositions();

		for (Point currentPoint : positions) {
			returnList.add(getMobOnPosition(currentPoint));
		}
		return returnList;
	}

	public Mob getMobOnPosition(Point pos) {
		List<GameElement> elementsOnSelectedField = getStepManager()
				.getElements(pos);
		if (elementsOnSelectedField.size() > 1)
			// TODO: casten ist evtl. problematisch...
			return (Mob) elementsOnSelectedField.get(elementsOnSelectedField
					.size() - 1);
		return null;
	}

	public void restoreState() {
		gameState = tempGameState;
	}

	public void saveState() {
		tempGameState = gameState;
	}

	public void changeTeam() {
		team1IsActive = !team1IsActive;
	}

	public boolean isTeam1IsActive() {
		return team1IsActive;
	}

	public XcomTeam getActiveTeam() {
		if (team1IsActive)
			return team1;
		return team2;
	}

	public XcomTeam getEnemyTeam() {
		if (team1IsActive)
			return team2;
		return team1;
	}

	public XcomTeam getTeam2() {
		return team2;
	}

	public List<Mob> getActiveTeamMobs() {
		return getMobs(team1IsActive);
	}

	public List<Mob> getEnemyTeamMobs() {
		return getMobs(!team1IsActive);
	}

	public void deleteMob(Mob killedMob) {
		if (team1.deleteMob(killedMob) && !team1.isDefeated()) {
			List<GameElement> field = this.getStepManager().getElements(
					team1.getMobPositions().get(0));
			if (field.get(field.size() - 1) instanceof Mob)
				team1.setSelectedMob((Mob) field.get(field.size() - 1));
			else
				throw new IllegalArgumentException(
						"an der angegebenen Position befindet sich kein Mob!");
		}
		if (team2.deleteMob(killedMob) && !team2.isDefeated()) {
			List<GameElement> field = this.getStepManager().getElements(
					team2.getMobPositions().get(0));
			if (field.get(field.size() - 1) instanceof Mob)
				team2.setSelectedMob((Mob) field.get(field.size() - 1));
			else
				throw new IllegalArgumentException(
						"an der angegebenen Position befindet sich kein Mob!");
		}
	}

	public void setLevel(String level) {
		this.level = level;
	}

	public String getLevel() {
		return level;
	}

	public String returnGameState() {
		String gameState = "";
		for (int i = 0; i < this.getStepManager().getHeight(); i++) {
			for (int j = 0; j < this.getStepManager().getWidth(); j++) {
				List<GameElement> currentField = this.getStepManager()
						.getElements(j, i);

				gameState += currentField.get(currentField.size() - 1)
						.toString();
			}
			gameState += "\n";
		}
		return gameState.trim();
	}

	public String getTopGameElement(int x, int y) {
		List<GameElement> currentField = this.getStepManager()
				.getElements(x, y);
		return currentField.get(currentField.size() - 1).toString();
	}

	public String getNextLevel() {
		return nextLevel;
	}

	public void setNextLevel(String string) {
		nextLevel = string;
	}

	public void setTeam2UseAi(int mode) {
		switch (mode) {
		case 0:
			team2.setAI(new XcomSimpleAI());
			break;
		case 1:
			team2.setAI(new XcomMediumAI());
			break;
		default:
			team2.setAI(new XcomSimpleAI());
		}
	}
}
